from __future__ import annotations

from typing import Any, ClassVar, Protocol, SupportsFloat, SupportsInt, TypeVar, final

from typing_extensions import Self

# Define a generic type variable for the protocol
_FT = TypeVar("_FT", bound="FloatNumeric")

# Define the union type for numeric inputs, including the new classes
class FloatNumeric(SupportsFloat, SupportsInt, Protocol):
    nan: ClassVar[Self]
    infinity: ClassVar[Self]
    negative_infinity: ClassVar[Self]

    # Define methods common to Float32 and Float64
    def __init__(self, value: SupportsInt | SupportsFloat) -> None: ...
    @property
    def value(self) -> float: ...  # Assuming value always returns standard float
    def __add__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __radd__(self: _FT, other: Any) -> _FT: ...
    def __sub__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __rsub__(self: _FT, other: Any) -> _FT: ...
    def __mul__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __rmul__(self: _FT, other: Any) -> _FT: ...
    def __truediv__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __rtruediv__(self: _FT, other: Any) -> _FT: ...
    def __floordiv__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __rfloordiv__(self: _FT, other: Any) -> _FT: ...
    def __mod__(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def __rmod__(self: _FT, other: Any) -> _FT: ...
    def __pow__(self: _FT, other: int | float | FloatNumeric, modulo: None = ...) -> _FT: ...
    def __neg__(self: _FT) -> _FT: ...
    def __pos__(self: _FT) -> _FT: ...
    def __abs__(self: _FT) -> _FT: ...
    def __eq__(self, other: Any) -> bool: ...
    def __ne__(self, other: Any) -> bool: ...
    def __lt__(self, other: int | float | FloatNumeric) -> bool: ...
    def __le__(self, other: int | float | FloatNumeric) -> bool: ...
    def __gt__(self, other: int | float | FloatNumeric) -> bool: ...
    def __ge__(self, other: int | float | FloatNumeric) -> bool: ...
    def __floor__(self: _FT) -> _FT: ...
    def __ceil__(self: _FT) -> _FT: ...
    def __trunc__(self: _FT) -> _FT: ...
    def __round__(self: _FT) -> _FT: ...
    def __hash__(self) -> int: ...
    def __bool__(self) -> bool: ...
    def __float__(self) -> float: ...
    def __index__(self) -> int: ...
    def __int__(self) -> int: ...
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __format__(self, format_spec: str) -> str: ...
    # Math operations
    def floor(self: _FT) -> _FT: ...
    def ceil(self: _FT) -> _FT: ...
    def round(self: _FT, n: int = 0) -> _FT: ...
    def sqrt(self: _FT) -> _FT: ...
    def sin(self: _FT) -> _FT: ...
    def cos(self: _FT) -> _FT: ...
    def tan(self: _FT) -> _FT: ...
    def sinh(self: _FT) -> _FT: ...
    def cosh(self: _FT) -> _FT: ...
    def tanh(self: _FT) -> _FT: ...
    def asin(self: _FT) -> _FT: ...
    def acos(self: _FT) -> _FT: ...
    def atan(self: _FT) -> _FT: ...
    def atan2(self: _FT, other: int | float | FloatNumeric) -> _FT: ...
    def exp(self: _FT) -> _FT: ...
    def log(self: _FT, base: int | float | FloatNumeric | None = None) -> _FT: ...
    def log10(self: _FT) -> _FT: ...
    def log2(self: _FT) -> _FT: ...
    def degrees(self: _FT) -> _FT: ...
    def radians(self: _FT) -> _FT: ...
    def is_nan(self: Any) -> bool: ...
    def is_infinity(self: Any) -> bool: ...
    def is_negative_infinity(self: Any) -> bool: ...
    def is_positive_infinity(self: Any) -> bool: ...

@final  # Mark classes as final as they are implemented in Rust
class Float32(FloatNumeric):
    nan: ClassVar[Self]
    infinity: ClassVar[Self]
    negative_infinity: ClassVar[Self]

@final
class Float64(FloatNumeric):
    nan: ClassVar[Self]
    infinity: ClassVar[Self]
    negative_infinity: ClassVar[Self]

# Module-level constants
infinity: Float64
negative_infinity: Float64
nan: Float64

# Free functions for mathematical operations
def sqrt(x: Float64) -> Float64: ...
def cos(x: Float64) -> Float64: ...
def sin(x: Float64) -> Float64: ...
def tan(x: Float64) -> Float64: ...
def sinh(x: Float64) -> Float64: ...
def cosh(x: Float64) -> Float64: ...
def tanh(x: Float64) -> Float64: ...
def acos(x: Float64) -> Float64: ...
def asin(x: Float64) -> Float64: ...
def atan(x: Float64) -> Float64: ...
def atan2(y: Float64, x: Float64) -> Float64: ...
def exp(x: Float64) -> Float64: ...
def log(x: Float64, base: float | None = None) -> Float64: ...
def log10(x: Float64) -> Float64: ...
def log2(x: Float64) -> Float64: ...
def degrees(x: Float64) -> Float64: ...
def radians(x: Float64) -> Float64: ...
def is_nan(x: Float64) -> bool: ...
def is_infinity(x: Float64) -> bool: ...
def is_positive_infinity(x: Float64) -> bool: ...
def is_negative_infinity(x: Float64) -> bool: ...
def floor(x: Float64) -> Float64: ...
def ceil(x: Float64) -> Float64: ...
def pow(x: Float64, y: float | FloatNumeric) -> Float64: ...
def parse(x: str) -> Float64: ...
def abs(x: Float64) -> Float64: ...

__all__ = [
    "Float32",
    "Float64",
    "acos",
    "asin",
    "atan",
    "atan2",
    "ceil",
    "cos",
    "degrees",
    "exp",
    "floor",
    "infinity",
    "is_infinity",
    "is_nan",
    "is_negative_infinity",
    "is_positive_infinity",
    "log",
    "log2",
    "log10",
    "nan",
    "negative_infinity",
    "pow",
    "radians",
    "sin",
    "sqrt",
    "tan",
]
